package com.itheima.search.listener;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.itheima.search.domain.News;
import com.itheima.search.domain.NewsVO;
import com.itheima.search.service.ISearchService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 * 消息监听类：用于监听 RabbitMQ 队列中的新闻消息，并将数据同步到 Elasticsearch。
 *
 * 支持三种操作：
 * - 新增新闻（insert）
 * - 更新新闻（update）
 * - 删除新闻（delete）
 */
@Component  // 将该类交给 Spring 容器管理
@Slf4j    // Lombok 注解，自动生成日志记录器 log
public class NewsMessageListener {

    /**
     * 注入搜索服务接口实现类，用于与 Elasticsearch 进行交互
     * 使用 @Qualifier 明确指定注入 "searchServiceImpl" 实例
     */
    @Autowired
    @Qualifier("searchServiceImpl")
    private ISearchService searchService;

    /**
     * 监听新增新闻队列：news.insert.queue
     *
     * 接收到消息后，将 JSON 字符串反序列化为 News 对象，
     * 转换为 NewsVO 并调用服务保存到 Elasticsearch。
     *
     * @param message RabbitMQ 发送的消息体（JSON 字符串）
     */
    @RabbitListener(queues = "news.insert.queue")
    public void processInsertMessage(String message) {
        try {
            log.info("新增，开始同步新闻到ES：{}", message);

            // 如果消息是双引号包裹的字符串，则去除外层引号并处理内部转义
            if (message != null && message.startsWith("\"") && message.endsWith("\"")) {
                message = message.substring(1, message.length() - 1).replace("\\\"", "\"");
            }

            // 解析 JSON 字符串为 JSONObject
            JSONObject jsonObject = JSONUtil.parseObj(message);
            // 转换为 News 实体对象
            News news = jsonObject.toBean(News.class);
            // 转换为 VO 对象以便后续操作
            NewsVO bean = BeanUtil.toBean(news, NewsVO.class);

            // 调用服务将新闻写入 Elasticsearch
            searchService.saveNewsToEs(bean);

            log.info("新闻已成功写入ES：{}", news.getTitle());

        } catch (Exception e) {
            log.error("同步新闻到ES失败：{}", message, e);
        }
    }

    /**
     * 监听更新新闻队列：news.update.queue
     *
     * 接收到消息后，解析 JSON 数据，转换为 NewsVO 并重新保存到 Elasticsearch。
     * ES 中相同 ID 的文档会被更新。
     *
     * @param message RabbitMQ 发送的消息体（JSON 字符串）
     */
    @RabbitListener(queues = "news.update.queue")
    public void processUpdateMessage(String message) {
        try {
            log.info("修改，开始同步新闻到ES：{}", message);

            // 去除外层引号并处理内部 JSON 转义
            if (message != null && message.startsWith("\"") && message.endsWith("\"")) {
                message = message.substring(1, message.length() - 1).replace("\\\"", "\"");
            }

            // 解析 JSON 字符串为 JSONObject
            JSONObject jsonObject = JSONUtil.parseObj(message);
            // 转换为 News 实体对象
            News news = jsonObject.toBean(News.class);

            // 转换为 VO 对象
            NewsVO bean = BeanUtil.toBean(news, NewsVO.class);

            // 调用服务将新闻写入 Elasticsearch（更新操作）
            searchService.saveNewsToEs(bean);

            log.info("新闻已成功写入ES：{}", news.getTitle());

        } catch (Exception e) {
            log.error("同步新闻到ES失败：{}", message, e);
        }
    }

    /**
     * 监听删除新闻队列：news.delete.queue
     *
     * 接收到消息后，解析出新闻ID，从 Elasticsearch 中删除对应文档。
     *
     * @param message RabbitMQ 发送的消息体（JSON 字符串）
     */
    @RabbitListener(queues = "news.delete.queue")
    public void processDeleteMessage(String message) {
        try {
            log.info("删除，开始同步新闻到ES：{}", message);

            // 去除外层引号并处理内部 JSON 转义
            if (message != null && message.startsWith("\"") && message.endsWith("\"")) {
                message = message.substring(1, message.length() - 1).replace("\\\"", "\"");
            }

            // 解析 JSON 字符串为 JSONObject
            JSONObject jsonObject = JSONUtil.parseObj(message);
            // 转换为 News 实体对象
            News news = jsonObject.toBean(News.class);

            // 转换为 VO 对象
            NewsVO bean = BeanUtil.toBean(news, NewsVO.class);

            // 调用服务从 Elasticsearch 中删除新闻
            searchService.deleteNewsFromEs(bean.getNewsId());

            log.info("新闻已成功从ES中删除：{}", news.getTitle());

        } catch (Exception e) {
            log.error("同步新闻到ES失败：{}", message, e);
        }
    }
}
